// Copyright (c) 2009, Michael Patraw
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * The name of Michael Patraw may not be used to endorse or promote 
//       products derived from this software without specific prior written
//       permission.
//
// THIS SOFTWARE IS PROVIDED BY Michael Patraw ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Michael Patraw BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sstream>

#include "MersenneTwister.h"
#include "weather.h"

extern MTRand mt;

const int SPRING_AVERAGE   = 18;
const int SUMMER_AVERAGE   = 25;
const int FALL_AVERAGE     = 17;
const int WINTER_AVERAGE   = 0;

const int AVG_DEV = 5;

Weather::Weather() :
ctemp_(20), forecast_(FORE_CLEAR), windmph_(0), dayupdated_(-1), hourupdated_(-1)
{

}

Weather::~Weather()
{

}

const char * Weather::getWeather() const
{
    std::stringstream ss;
    
    ss << ctemp_ << "C";
    
    if (forecast_ == FORE_CLEAR) {
        ss << ", clear";
    }
    else if (forecast_ == FORE_CLOUDY) {
        ss << ", cloudy";
    }
    else if (forecast_ == FORE_STORMY) {
        if (ctemp_ <= 0)
            ss << ", snowing";
        else
            ss << ", raining";
    }
    
    ss << ", " << windmph_ << "mph gusts";
    
    return ss.rdbuf()->str().c_str();
}

int Weather::getCTemperature() const
{
    return ctemp_;
}

int Weather::getForecast() const
{
    return forecast_;
}

int Weather::getWind() const
{
    return windmph_;
}

int Weather::getCTempMod() const
{
    if (ctemp_ > ROOM_CTEMP_MAX) {
        return ctemp_ - ROOM_CTEMP_MAX;
    }
    // -0.5 until at 10C then -1 after that.
    else if (ctemp_ < ROOM_CTEMP_MIN) {
        int i = 0;
        double total = 0;
        while (i < ROOM_CTEMP_MIN - ctemp_) {
            if (i < 10)
                total -= 0.5;
            else
                total -= 1;
            ++i;
        }
        return (int)total;
    }
    else {
        return 0;
    }
}

void Weather::update(const Time & time)
{
    if (time.getDay() > dayupdated_) {
        forecast_ = mt.randInt(NUM_FORECASTS - 1);
        windmph_ = mt.randInt(100) - 50;
        if (windmph_ < 0)
            windmph_ = 0;
        switch (time.getSeason()) {
            case SPRING:
                ctemp_ = (mt.randInt(AVG_DEV*2) - AVG_DEV) + SPRING_AVERAGE;
                break;
            case SUMMER:
                ctemp_ = (mt.randInt(AVG_DEV*2) - AVG_DEV) + SUMMER_AVERAGE;
                break;
            case FALL:
                ctemp_ = (mt.randInt(AVG_DEV*2) - AVG_DEV) + FALL_AVERAGE;
                break;
            case WINTER:
                ctemp_ = (mt.randInt(AVG_DEV*2) - AVG_DEV) + WINTER_AVERAGE;
                break;
        }
        
        dayupdated_ = time.getDay();
    }
    // Hourly updates.
    if (time.getHour() > hourupdated_) {
        if (time.isDay()) {
            ctemp_ += mt.randInt(1);
        }
        else if (time.isNight()) {
            ctemp_ -= mt.randInt(1);
        }
        
        hourupdated_ = time.getHour();
    }
}
